#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* To get pthread_getattr_np() declaration */
#endif
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include "create_pthread.h"
#include "pthread_info.h"
#define handle_error_en(en, msg) \
    do                           \
    {                            \
        errno = en;              \
        perror(msg);             \
        exit(EXIT_FAILURE);      \
    } while (0)
int create_pthread( pthread_t *t, pthread_entry fun, void *arg, int policy, int stack_size, int isdetach,int priority)
{
    pthread_attr_t attr;
    pthread_attr_t *attrp; /* NULL or &attr */
    int s;
    attrp = NULL;
    void *sp;

    attrp = &attr;

    s = pthread_attr_init(&attr);
    if (s != 0)
        handle_error_en(s, "pthread_attr_init");
    if(isdetach>0){
        s = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
        if (s != 0)
            handle_error_en(s, "pthread_attr_setdetachstate");

    }
    if(policy>0){
        
        s = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
        if (s != 0)
            handle_error_en(s, "pthread_attr_setinheritsched");

	    pthread_attr_setschedpolicy(&attr, policy);
        if(priority>0){
            struct sched_param priparam;
            priparam.sched_priority = priority;//  99;
	        pthread_attr_setschedparam(&attr, &priparam);
        }
	   
    }

    if(stack_size>0){
         s = posix_memalign(&sp, sysconf(_SC_PAGESIZE), stack_size);
        if (s != 0)
            handle_error_en(s, "posix_memalign");

        printf("posix_memalign() allocated at %p\n", sp);

        s = pthread_attr_setstack(&attr, sp, stack_size);
        if (s != 0)
            handle_error_en(s, "pthread_attr_setstack");

    }
   
    s = pthread_create(t, attrp, fun, arg);
    if (s != 0)
        handle_error_en(s, "pthread_create");

    if (attrp != NULL)
    {
        s = pthread_attr_destroy(attrp);
        if (s != 0)
            handle_error_en(s, "pthread_attr_destroy");
    }
    return 0;

}

static void *thread1(void *arg)
{
    const char *tag =(const char *)arg;
    pthread_attr_t attr;
    int policy=0;
    struct sched_param param;
    pthread_getattr_np(pthread_self(), &attr);
    printf("\n%s Thread attributes:\n",tag);
    display_pthread_attr(&attr,(char*)tag);
    return (NULL);
}
int create_pthread_fun_test(void)
{
    pthread_t t1;
    pthread_t t2;
    pthread_t t3;
    pthread_t t4;
    pthread_t t5;
    create_pthread(&t1,thread1,"thread1",SCHED_RR,-1,-1,50);
    create_pthread(&t2,thread1,"thread2",SCHED_FIFO,-1,-1,60);
    create_pthread(&t3,thread1,"thread3",-1,1024*1024*4,-1,10);
    
    pthread_join(t1,NULL);
    pthread_join(t2,NULL);
    pthread_join(t3,NULL);
    return 0;
}